/*
 * BLDC_Motor.c
 * $HeadURL: http://bldc-motor.googlecode.com/svn/trunk/Software/BLDC-Motor.c $
 * $Revision: 8 $
 *
 * Created: 23.08.2012 14:03:00
 * $LastChangedDate: 2012-09-05 20:27:31 +0000 (Wed, 05 Sep 2012) $
 
 * Author: Jens
 * $Author: boecki91@gmail.com $
 */ 

#define F_CPU 20000000UL
#define BAUDRATE 250000UL
#define TERMINAL_PAIRS 4
//#define DEBUG
#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "portdef.h"
#include "usart.h"
volatile uint8_t tick = 0;
volatile uint8_t state = 2;

volatile uint16_t adc_result[8];

volatile uint8_t adcom = 0;
void bldc_start(void);
volatile uint8_t BEMF_activ = 0;
int main(void)
{
	//Initalisise ports
	DDRB = DDRB_INIT;
	DDRC = DDRC_INIT;
	DDRD = DDRD_INIT;
	
	USART_init (UART_BAUD_SELECT(BAUDRATE,F_CPU));
	sei();
	//Because of a long Start-Up time we say hello at first
	USART_puts("BLDC-Motor-Control\r\n$Revision: 8 $\r\nBuild: ");
	USART_puts(__DATE__);
	USART_puts(" ");
	USART_puts(__TIME__);
	USART_puts("\r\n");
	//Wait until everything is transmitted
	
	//Interrupts off again
	cli();
	//20kHz Timer/Counter
	TCCR1A = _BV(WGM11);
	TCCR1B = _BV(WGM13)| _BV(WGM13)| _BV(CS10);
	ICR1 = 500;
	OCR1A = 350;
	
	/* ADC
	// Use AVCC as Reference
	ADMUX = _BV(REFS0);
	// Prescale with 128
	//Samplingrate must be between 50kHz and 200kHz
	// Its 156,250kHz now
	ADCSRA = _BV(ADEN) | _BV(ADPS0) | _BV(ADPS1) | _BV(ADPS2) | _BV(ADIE);
	///
	//Start a Readout, the Interrupt will do the rest
	ADCSRA |= (1<<ADSC);
	//*/
	//Analog Compare
	ADCSRB = _BV(ACME);
	ADCSRA = _BV(MUX1) |_BV(MUX0);
	ACSR = _BV(ACIE) | _BV(ACIS1) | _BV(ACIS0);
	ADCSRA |= (1<<ADSC);
	//*/
	
	
	// Interrupt for PWM
	TIMSK1 = _BV(OCIE1A)| _BV(TOIE1);
	sei();

	BEMF_activ = 0;
	uint8_t ms_help = 0;
	uint16_t delay = 1000;
	uint16_t delay_time = 1000;
	uint32_t ms =0;
	while(1)
	{
// 		//_delay_ms(10);
// 		//state++;
// 		if(BEMF_activ < 100)
// 		{
// 			bldc_start();
// 		}
// 		if(BEMF_activ > 100)
// 		{
// 			//OCR1A = 470;
// 		}
		
		/*
		for(uint8_t i = 1; i<4; i++)
		{
			USART_puti(i);
			USART_puts(": ");
			USART_puti(adc_result[i]);
			USART_puts("\t");				
		}*/
		USART_puti(state);
			USART_puts("\r\n");
		
#ifdef DEBUG
		switch (state)
		{
			case 0:
				USART_puts("A: PWM      B:flaoting C: GND      \r\n");
			break;
			case 1:
				USART_puts("A: flaoting B:PWM      C: GND      \r\n");
			break;
			case 2:
				USART_puts("A: GND      B:PWM      C: flaoting \r\n");
			break;
			case 3:
				USART_puts("A: GND      B:flaoting C: PWM      \r\n");
			break;
			case 4:
				USART_puts("A: flaoting B:GND      C: PWM      \r\n");
			break;
			case 5:
				USART_puts("A: PWM      B:GND      C: flaoting \r\n");
			break;
			default:
				USART_puts("FATAL ERROR");
			break;
		}
#endif // DEBUG
	}		
}
ISR(TIMER1_COMPA_vect)
{
	if (state >= 6)
	{
		state = 0;
	}
	switch(state)
	{
		case 0:
			PORTD ^= _BV(A_IN);		// A_IN: PWM
			PORTD |= _BV(A_SD);		// A_SD: ON		-> A: PWM

			PORTB &= ~_BV(B_IN);	// B_IN: OFF
			PORTB &= ~_BV(B_SD);	// B_SD: OFF	-> B: FLOATING

			PORTD &= ~_BV(C_IN);	// C_IN: OFF
			PORTD |= _BV(C_SD);		// C_SD: ON		-> C: GND
		break;
		case 1:
			PORTD &= ~_BV(A_IN);	// A_IN: OFF
			PORTD &= ~_BV(A_SD);	// A_SD: OFF	-> A: FLOATING
			

			PORTB ^= _BV(B_IN);		// B_IN: PWM
			PORTB |= _BV(B_SD);		// B_SD: ON		-> B: PWM

			PORTD &= ~_BV(C_IN);	// C_IN: OFF
			PORTD |= _BV(C_SD);		// C_SD: ON		-> C: GND
		break;
		case 2:
			PORTD &= ~_BV(A_IN);	// A_IN: OFF
			PORTD |= _BV(A_SD);		// A_SD: ON		-> A: GND
	

			PORTB ^= _BV(B_IN);		// B_IN: PWM
			PORTB |= _BV(B_SD);		// B_SD: ON		-> B: PWM
		
			PORTD &= ~_BV(C_IN);	// C_IN: OFF
			PORTD &= ~_BV(C_SD);	// C_SD: OFF	-> C: FLOATING*/
		break;
		case 3:
			PORTD &= ~_BV(A_IN);	// A_IN: OFF
			PORTD |= _BV(A_SD);		// A_SD: ON		-> A: GND
			

			PORTB &= ~_BV(B_IN);	// B_IN: OFF
			PORTB &= ~_BV(B_SD);	// B_SD: OFF	-> B: FLOATING

			PORTD ^= _BV(C_IN);		// C_IN: PWM
			PORTD |= _BV(C_SD);		// C_SD: ON		-> C: PWM*/
		break;
		case 4:
			PORTD &= ~_BV(A_IN);	// A_IN: OFF
			PORTD &= ~_BV(A_SD);	// A_SD: OFF	-> A: FLOATING
			

			PORTB &= ~_BV(B_IN);	// B_IN: OFF
			PORTB |= _BV(B_SD);		// B_SD: ON		-> B: GND
			
			PORTD ^= _BV(C_IN);		// C_IN: PWM
			PORTD |= _BV(C_SD);		// C_SD: ON		-> C: PWM
		break;
		case 5:
			PORTD ^= _BV(A_IN);		// A_IN: PWM
			PORTD |= _BV(A_SD);		// A_SD: ON		-> A: PWM		

			PORTB &= ~_BV(B_IN);	// B_IN: OFF
			PORTB |= _BV(B_SD);		// B_SD: ON		-> B: GND
			
			PORTD &= ~_BV(C_IN);	// C_IN: OFF
			PORTD &= ~_BV(C_SD);	// C_SD: OFF	-> C: FLOATING*/
		break;
	}	
}

ISR(TIMER1_OVF_vect)
{
	// Quick & Dirty Workaround for correct toggling
	PORTD &= ~_BV(A_IN);
	PORTB &= ~_BV(B_IN);
	PORTD &= ~_BV(C_IN);
	tick = 1;
}

void bldc_start(void)
{
	state++;
	static uint16_t delay = 17000;
	static uint16_t rounds = 0;

	for(uint16_t i= 0; i <delay; i++)
	{
		_delay_us(1);
	}
	
	if (state >= 5)
	{
		rounds++;
		if(delay > 4000)
		{
			delay-=200;
			OCR1A = 300;
		}
		else if(delay > 1000)
		{
			delay-=10;
			OCR1A = 300;
		}
		else if(delay > 800)
		{
			delay-=1;
			OCR1A = 250;
		}
		else if(delay > 700)
		{
			delay-=1;
			OCR1A = 200;
		}
		else if(delay > 500)
		{
			delay-=1;
			OCR1A = 150;
		}
		else if(delay > 380)
		{
			delay-=1;
			OCR1A = 100;
		}
		else
		{
			if(OCR1A <300)
			{
				OCR1A = 300;
			}
		}
	}				
}


ISR(ADC_vect)
{
	static uint8_t channel = 0;
	adc_result[channel++] = ADCW;
	ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
	ADCSRA |= (1<<ADSC);
}
ISR(ANALOG_COMP_vect)
{
	state++;
	if(state >=6)
	{
		state = 0;
	}
	ADCSRA = (ADCSRA & ~(0x1F)) | (state & 0x1F);
}